#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>
#include <sys/time.h>

#define PACKET_SIZE 64
#define MAX_WAIT_TIME 5
#define MAX_NO_PACKETS 3

unsigned short cal_chksum(unsigned short *addr, int len) {
    int nleft = len;
    int sum = 0;
    unsigned short *w = addr;
    unsigned short answer = 0;

    while (nleft > 1) {
        sum += *w++;
        nleft -= 2;
    }

    if (nleft == 1) {
        *(unsigned char *)(&answer) = *(unsigned char *)w;
        sum += answer;
    }

    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;
    return answer;
}

void send_packet(int sockfd, struct sockaddr_in *dest_addr) {
    int packets_sent = 0;
    char sendpacket[PACKET_SIZE];

    while (packets_sent < MAX_NO_PACKETS) {
        memset(sendpacket, 0, PACKET_SIZE);
        struct icmp *icmp_hdr = (struct icmp *)sendpacket;
        icmp_hdr->icmp_type = ICMP_ECHO;
        icmp_hdr->icmp_code = 0;
        icmp_hdr->icmp_cksum = 0;
        icmp_hdr->icmp_seq = packets_sent;
        icmp_hdr->icmp_id = getpid();
        icmp_hdr->icmp_cksum = cal_chksum((unsigned short *)icmp_hdr, PACKET_SIZE);

        sendto(sockfd, sendpacket, PACKET_SIZE, 0, (struct sockaddr *)dest_addr, sizeof(*dest_addr));
        packets_sent++;
        sleep(1);
    }
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        std::cerr << "Usage: " << argv[0] << " <destination IP>" << std::endl;
        return 1;
    }

    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sockfd < 0) {
        std::cerr << "Socket creation failed" << std::endl;
        return 1;
    }

    struct sockaddr_in dest_addr;
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_addr.s_addr = inet_addr(argv[1]);

    send_packet(sockfd, &dest_addr);
    close(sockfd);
    return 0;
}    